package ferp.android.engagement;

import android.app.Activity;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.*;
import android.widget.FrameLayout;
import android.widget.ImageView;
import ferp.android.GUI;
import ferp.android.R;
import ferp.core.log.Log;

import java.util.LinkedList;
import java.util.Random;

/**
 * User: igorgok
 * Date: 12/25/12 10:31 AM
 */
public final class Snowfall
{
  public Snowfall(Activity activity, final ViewGroup target)
  {
    this.activity = activity;
    this.target = target;

    target.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
    {
      @Override
      public void onGlobalLayout()
      {
        Log.debug(Log.TAG, "onGlobalLayout received");

        // make sure this happens only once
        GUI.removeGlobalOnLayoutListener(target, this);

        // we can start the snowfall
        Snowfall.this.setReady();
        Snowfall.this.start();
      }
    });
  }

  public final void start()
  {
    // do not start if not ready
    if (!isReady())
    {
      Log.debug(Log.TAG, "layout is not ready yet, can't start the snowfall");

      return;
    }

    Log.debug(Log.TAG, "starting snowfall animation on " + target.getWidth() + "x" + target.getHeight() + " area");

    // calculate the number of snowflakes to show: sqrt(sqrt(area)) * 2
    final long nsf = Math.round(Math.sqrt(Math.sqrt(target.getWidth() * target.getHeight()))) * 2;

    Log.debug(Log.TAG, "number of snowflakes: " + nsf);

    for (int i = 0; i < nsf; ++i)
    {
      final ImageView iv = new ImageView(activity);

      iv.setImageResource(toss(0.05f) ? R.drawable.sf02 : (toss(0.05f) ? R.drawable.sf03 : (toss(0.3f) ? R.drawable.sf00 : R.drawable.sf01)));
      iv.setAdjustViewBounds(true);

      target.addView(iv);
      snowflakes.add(iv);

      setup(iv, true);
    }
  }

  public synchronized void setReady() {ready = true;}
  public synchronized boolean isReady() {return ready;}

  public final void stop()
  {
    for (ImageView iv : snowflakes)
    {
      iv.clearAnimation();
      iv.setVisibility(View.INVISIBLE);

      GUI.recycle(iv.getDrawable());
      iv.setImageDrawable(null);
    }
  }

  private static Random random = new Random();

  private final Activity activity;
  private final ViewGroup target;
  private final LinkedList<ImageView> snowflakes = new LinkedList<ImageView>();
  private boolean ready = false;

  private void setup(final ImageView iv, boolean first)
  {
    int left = random.nextInt(target.getWidth() - iv.getDrawable().getMinimumWidth());
    int top = first ? random.nextInt(target.getHeight()) : -iv.getDrawable().getMinimumHeight();
    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.NO_GRAVITY);

    lp.setMargins(left, top, 0, 0);
    iv.setLayoutParams(lp);

    Animation appear = new AlphaAnimation(0, 1);

    appear.setDuration((first ? 5000 : 500) + random.nextInt(100) * 15);
    appear.setInterpolator(new AccelerateInterpolator());
    appear.setRepeatCount(0);

    // determine rotation
    Animation rotate = toss() ?
        new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0f):
        new RotateAnimation(360, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0f);

    rotate.setDuration(12000 + random.nextInt(50) * 200);
    rotate.setInterpolator(new LinearInterpolator());
    rotate.setRepeatCount(Animation.INFINITE);
    rotate.setRepeatMode(Animation.REVERSE);

    double h = target.getHeight() - top;
    double time = 14000 + random.nextInt(50) * 200;
    Animation fall = new TranslateAnimation(0, 0, 0, Math.round(h));

    fall.setFillAfter(true);
    fall.setDuration(Math.round(time / target.getHeight() * h));
    fall.setInterpolator(new LinearInterpolator());
    fall.setRepeatCount(0);
    fall.setAnimationListener(new Animation.AnimationListener()
    {
      @Override
      public void onAnimationStart(Animation animation)
      {
      }

      @Override
      public void onAnimationEnd(Animation animation)
      {
        // reuse the snowflake
        setup(iv, false);
      }

      @Override
      public void onAnimationRepeat(Animation animation)
      {
      }
    });

    // combine animations
    AnimationSet set = new AnimationSet(false);

    set.addAnimation(appear);
    set.addAnimation(rotate);
    set.addAnimation(fall);

    iv.startAnimation(set);
  }

  private boolean toss() {return toss(0.5f);}
  private boolean toss(float probability)
  {
    return random.nextFloat() <= probability;
  }
}
